package com.easyjava.vuebuilder;

import com.easyjava.bean.Constants;
import com.easyjava.bean.FieldInfo;
import com.easyjava.bean.TableInfo;
import com.easyjava.utils.MyStringUtils;
import com.easyjava.vuebean.ConstantsVue;
import org.apache.commons.lang3.ArrayUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.*;
import java.nio.charset.StandardCharsets;
import java.util.List;
import java.util.Map;
import java.util.Set;

/**
 * @Author: 小闹心
 * @Description: 创建vue界面
 * @DateTime: 2024/11/21 13:27
 **/
public class BuilderVue {
    public static final Logger logger = LoggerFactory.getLogger(BuilderVue.class);
    public static void execute(TableInfo tableInfo){
        String beanName = MyStringUtils.lowerCaseFirstLetter(tableInfo.getBeanName());
        File folder = new File(ConstantsVue.PATH_VUE_VIEWS);
        if(!folder.exists()){
            folder.mkdirs();
        }
        File javaFile = new File(folder,beanName + "-show.vue");
        OutputStream out = null;
        OutputStreamWriter outWriter = null;
        BufferedWriter bw = null;
        try{
            out = new FileOutputStream(javaFile);
            outWriter = new OutputStreamWriter(out, StandardCharsets.UTF_8);
            bw = new BufferedWriter(outWriter);
            bw.write("<template>");
            bw.newLine();
            bw.write("\t<div>");
            bw.newLine();
            bw.write("\t\t<el-button type=\"primary\"  @click=\"insert" + tableInfo.getBeanName()
                    + "\" style=\"width: 20vw; margin-bottom: 0.3vw;\">添加" + tableInfo.getComment() + "信息</el-button>");
            bw.newLine();
            for(FieldInfo fieldInfo : tableInfo.getFieldEnumList()){
                String comment = fieldInfo.getComment();
                int i = comment.indexOf(" ");
                comment = i == -1 ? comment : comment.substring(0,i);
                bw.write("\t\t<el-select v-model=\"" + beanName + "PageItem." + MyStringUtils.lowerCaseFirstLetter(fieldInfo.getPropertyName()) + "\" placeholder=\"请选择" + comment +"\" @change=\"getPage" + tableInfo.getBeanName() + "\" style=\"width: 10vw;margin-left: 0.5vw;\">");
                bw.newLine();
                bw.write("\t\t\t<el-option v-for=\"item in " + MyStringUtils.lowerCaseFirstLetter(fieldInfo.getPropertyName()) + "PageItemOptions\" :key=\"item.value\" :label=\"item.label\" :value=\"item.value\"/>");
                bw.newLine();
                bw.write("\t\t</el-select>");
                bw.newLine();
            }
            bw.write("\t\t<!-- " + tableInfo.getComment() + "分页展示 -->");
            bw.newLine();
            bw.write("\t\t<el-table :data=\"" + beanName +"Table\" border style=\"width: 100%\">");
            bw.newLine();
            List<FieldInfo> fieldEnumList = tableInfo.getFieldEnumList();
            Map<String, List<FieldInfo>> keyIndexMap = tableInfo.getKeyIndexMap();
            for(FieldInfo fieldInfo : tableInfo.getFieldList()){
                List<FieldInfo> keys = keyIndexMap.get("PRIMARY");
                if(ConstantsVue.IGNORE_VUE_KEYS && keys != null && !keys.isEmpty()){
                    if(keys.contains(fieldInfo)){
                        continue;
                    }
                }
                if(fieldEnumList.contains(fieldInfo)){
                    String comment = fieldInfo.getComment();
                    int i = comment.indexOf(" ");
                    comment = i == -1 ? comment : comment.substring(0,i);
                    bw.write("\t\t\t<el-table-column prop=\"" + MyStringUtils.lowerCaseFirstLetter(fieldInfo.getPropertyName()) + ".status\" label=\"" + comment + " \"/>");
                    bw.newLine();
                } else{
                    bw.write("\t\t\t<el-table-column prop=\"" + MyStringUtils.lowerCaseFirstLetter(fieldInfo.getPropertyName()) + "\" label=\"" + fieldInfo.getComment() + " \"/>");
                    bw.newLine();
                }
            }
            bw.write("\t\t\t<el-table-column fixed=\"right\" label=\"操作\" min-width=\"120\">");
            bw.newLine();
            bw.write("\t\t\t\t<template #default=\"scope\">");
            bw.newLine();
            bw.write("\t\t\t\t\t<el-button link type=\"primary\" size=\"small\" @click=\"update" + tableInfo.getBeanName()
                    + "(scope.row)\">修改</el-button>");
            bw.newLine();
            bw.write("\t\t\t\t\t<el-button link type=\"primary\" size=\"small\" @click=\"delete" + tableInfo.getBeanName()
                    + "(scope.row)\">删除</el-button>");
            bw.newLine();
            bw.write("\t\t\t\t</template>");
            bw.newLine();
            bw.write("\t\t\t</el-table-column>");
            bw.newLine();
            bw.write("\t\t</el-table>");
            bw.newLine();
            bw.newLine();

            bw.write("\t\t<!-- 分页条 -->");
            bw.newLine();
            bw.write("\t\t\t\t<div class=\"demo-pagination-block\" style=\"background-color: white; display: flex; justify-content: center;\">");
            bw.newLine();
            bw.write("\t\t\t<el-pagination v-model:current-page=\"" + beanName + "PageItem.page\" v-model:page-size=\"" + beanName + "PageItem.size\"");
            bw.newLine();
            bw.write("\t\t\t:page-sizes=\"[5, 10, 15]\" :disabled=\"false\" :background=\"true\"");
            bw.newLine();
            bw.write("\t\t\tlayout=\"sizes, prev, pager, next\" :total=\"" + beanName + "PageShow.totalCount\" @size-change=\"getPage" + tableInfo.getBeanName() + "\"");
            bw.newLine();
            bw.write("\t\t\t@current-change=\"getPage" + tableInfo.getBeanName() + "\" />");
            bw.newLine();
            bw.write("\t\t</div>");
            bw.newLine();

            bw.write("\t\t<!-- " + tableInfo.getComment() + "添加或者修改 -->");
            bw.newLine();
            bw.write("\t\t<el-dialog v-model=\"" + beanName + "Visible\" :title=\"" + beanName + "Form.id == null ? '添加" + tableInfo.getComment() + "信息' : '修改" + tableInfo.getComment() + "信息'\" width=\"500\">");
            bw.newLine();
            bw.write("\t\t\t<el-form :model=\"" + beanName + "Form\" :rules=\"" + beanName + "Rules\" ref=\"" + beanName + "SummitRef\">");
            bw.newLine();
            Set<Map.Entry<String, List<FieldInfo>>> entries = tableInfo.getKeyIndexMap().entrySet();
            Map.Entry<String, List<FieldInfo>> entry = entries.iterator().next();
            List<FieldInfo> keyFields = entry.getValue();
            for(FieldInfo fieldInfo : tableInfo.getFieldList()){
                if(ArrayUtils.contains(ConstantsVue.IGNORE_VUE_FIELDS,MyStringUtils.lowerCaseFirstLetter(fieldInfo.getPropertyName()))
                    || keyFields.contains(fieldInfo)){
                    continue;
                }
                if(fieldEnumList.contains(fieldInfo)){
                    String comment = fieldInfo.getComment();
                    int i = comment.indexOf(" ");
                    comment = i == -1 ? comment : comment.substring(0,i);
                    bw.write("\t\t\t\t<el-form-item label=\"" + comment + "\" prop=\"" + MyStringUtils.lowerCaseFirstLetter(fieldInfo.getPropertyName()) + "\">");
                    bw.newLine();
                    bw.write("\t\t\t\t\t<el-select v-model=\"" + beanName + "Form." + MyStringUtils.lowerCaseFirstLetter(fieldInfo.getPropertyName()) + "\" placeholder=\""
                            + "请选择" + comment + "\">");
                    bw.newLine();
                    bw.write("\t\t\t\t\t\t<el-option v-for=\"item in " + MyStringUtils.lowerCaseFirstLetter(fieldInfo.getPropertyName()) + "Options\" :key=\"item.value\" :label=\"item.label\" :value=\"item.value\"/>");
                    bw.newLine();
                    bw.write("\t\t\t\t\t</el-select>");
                    bw.newLine();
                    bw.write("\t\t\t\t</el-form-item>");
                    bw.newLine();
                }else {
                    bw.write("\t\t\t\t<el-form-item label=\"" + fieldInfo.getComment() + "\" prop=\"" + MyStringUtils.lowerCaseFirstLetter(fieldInfo.getPropertyName()) + "\">");
                    bw.newLine();
                    bw.write("\t\t\t\t\t<el-input v-model=\"" + beanName + "Form." + MyStringUtils.lowerCaseFirstLetter(fieldInfo.getPropertyName())
                            + "\" autocomplete=\"off\" />");
                    bw.newLine();
                    bw.write("\t\t\t\t</el-form-item>");
                    bw.newLine();
                }
            }
            bw.write("\t\t\t</el-form>");
            bw.newLine();
            bw.write("\t\t\t<template #footer>");
            bw.newLine();
            bw.write("\t\t\t\t<div class=\"dialog-footer\">");
            bw.newLine();
            bw.write("\t\t\t\t\t<el-button @click=\"resetUpload" + tableInfo.getBeanName() + "Form\">重置</el-button>");
            bw.newLine();
            bw.write("\t\t\t\t\t<el-button type=\"primary\" @click=\"summit" + tableInfo.getBeanName() +  "(" + beanName + "SummitRef" + ")\">提交</el-button>");
            bw.newLine();
            bw.write("\t\t\t\t</div>");
            bw.newLine();
            bw.write("\t\t\t</template>");
            bw.newLine();
            bw.write("\t\t</el-dialog>");
            bw.newLine();

            bw.write("\t</div>");
            bw.newLine();
            bw.write("</template>");
            bw.newLine();
            bw.newLine();

            bw.write("<script setup>");
            bw.newLine();
            bw.write("import '@/../node_modules/element-plus/dist/index.css/'");
            bw.newLine();
            // 设定添加规则
            bw.write("// 规则");
            bw.newLine();
            bw.write("const " + beanName + "Rules = {");
            bw.newLine();
            for(FieldInfo fieldInfo : tableInfo.getFieldList()){
                if(ArrayUtils.contains(ConstantsVue.IGNORE_VUE_FIELDS,MyStringUtils.lowerCaseFirstLetter(fieldInfo.getPropertyName()))
                        || keyFields.contains(fieldInfo)){
                    continue;
                }
                bw.write("\t" + MyStringUtils.lowerCaseFirstLetter(fieldInfo.getPropertyName()) + ": [ { trigger: 'blur', required: true, message: '不能为空' } ],");
                bw.newLine();
            }
            bw.write("}");
            bw.newLine();
            bw.newLine();
            // 找到主键修改的方法
            int index = 0;
            // getBy xxx方法
            StringBuilder methodName = new StringBuilder();
            // 方法参数 不带类型
            StringBuilder execParam = new StringBuilder();
            for(FieldInfo fieldInfo : keyFields){
                index++;
                methodName.append(MyStringUtils.upperCaseFirstLetter(MyStringUtils.lowerCaseFirstLetter(fieldInfo.getPropertyName())));
                execParam.append("row." + MyStringUtils.lowerCaseFirstLetter(fieldInfo.getPropertyName()));
                if(index < keyFields.size()){
                    methodName.append("And");
                    execParam.append(", ");
                }
            }

            // 导包区域
            bw.write("import { add" + tableInfo.getBeanName() + ", delete" + tableInfo.getBeanName() + "By" + methodName + ", get" + tableInfo.getBeanName() + "ByPage, update" + tableInfo.getBeanName() + "By" + methodName + " } from '@/apis/" + beanName + "API';");
            bw.newLine();
            bw.write("import { ElMessage, ElMessageBox } from 'element-plus';");
            bw.newLine();
            bw.write("import { onMounted, reactive, ref } from 'vue';");
            bw.newLine();
            bw.newLine();

            bw.write("//分页返回接收变量");
            bw.newLine();
            bw.write("const " + beanName + "PageShow = reactive({");
            bw.newLine();
            bw.write("\t'totalCount': 0");
            bw.newLine();
            bw.write("})");
            bw.newLine();
            bw.write("");
            bw.write("// 定义分页请求变量");
            bw.newLine();
            bw.write("const " + beanName + "PageItem = reactive({");
            bw.newLine();
            bw.write("\t'page': 1,");
            bw.newLine();
            bw.write("\t'size': 10,");
            bw.newLine();
            for(FieldInfo fieldInfo : tableInfo.getFieldList()){
                bw.write("\t'" + MyStringUtils.lowerCaseFirstLetter(fieldInfo.getPropertyName()) + "': null,");
                bw.newLine();
            }
            for(FieldInfo fieldInfo : tableInfo.getFieldExtendList()){
                bw.write("\t'" + MyStringUtils.lowerCaseFirstLetter(fieldInfo.getPropertyName()) + "': null,");
                bw.newLine();
            }
            bw.write("})");
            bw.newLine();
            bw.newLine();

            String beanNameForm = beanName + "Form";
            bw.write("// 定义添加或修改数据的请求变量");
            bw.newLine();
            bw.write("const " + beanNameForm + " = reactive({");
            bw.newLine();
            for(FieldInfo fieldInfo : tableInfo.getFieldList()){
                bw.write("\t'" + MyStringUtils.lowerCaseFirstLetter(fieldInfo.getPropertyName()) + "':null,");
                bw.newLine();
            }
            bw.write("})");
            bw.newLine();
            bw.newLine();

            bw.write("// 重置上传提交表单中的除去主键的数据");
            bw.newLine();
            bw.write("const resetUpload" + tableInfo.getBeanName() + "Form" + " = () => {");
            bw.newLine();
            for(FieldInfo fieldInfo : tableInfo.getFieldList()){
                if(!keyFields.contains(fieldInfo)){
                    bw.write("\t" + beanNameForm + "." + MyStringUtils.lowerCaseFirstLetter(fieldInfo.getPropertyName()) + " = null;");
                    bw.newLine();
                }
            }
            bw.write("}");
            bw.newLine();

            bw.write("// 分页请求模块");
            bw.newLine();
            bw.write("const " + beanName + "Table = ref([]);");
            bw.newLine();
            bw.write("const getPage" + tableInfo.getBeanName() + " = () => {");
            bw.newLine();
            bw.write("\tget" + tableInfo.getBeanName() + "ByPage(" + beanName + "PageItem).then(res => {");
            bw.newLine();
            bw.write("\t\tif(res.data.code == 200){");
            bw.newLine();
            bw.write("\t\t\t" + beanName + "Table.value = res.data.data.list;");
            bw.newLine();
            bw.write("\t\t\t" + beanName + "PageShow.totalCount = res.data.data.totalCount;");
            bw.newLine();
            bw.write("\t\t}");
            bw.newLine();
            bw.write("\t}).catch((error) => {");
            bw.newLine();
            ElementMessage(bw,"error.message","error","\t\t");
            bw.write("\t})");
            bw.newLine();
            bw.write("}");
            bw.newLine();
            bw.newLine();

            // // 添加修改
            //const categoryVisible = ref(true)
            bw.write("// // 添加修改");
            bw.newLine();
            bw.write("const " + beanName + "Visible = ref(false)");
            bw.newLine();
            for(FieldInfo fieldInfo : fieldEnumList){
                bw.write("const " + MyStringUtils.lowerCaseFirstLetter(fieldInfo.getPropertyName()) + "Options = [");
                bw.newLine();
                String comment = fieldInfo.getComment();
                String[] split = comment.split(" ", 2);
                String enumNames = "";
                if(split.length > 1){
                    enumNames = split[1];
                }else {
                    enumNames = split[0];
                }
                // 对枚举名称进行处理，携程枚举模式
                String[] names = enumNames.split(Constants.DB_COMMENT_ENUM_INTERVAL);
                for (String name : names) {
                    String[] codeAndStatus = getCodeAndStatus(name);
                    if (codeAndStatus == null) {
                        continue;
                    }
                    bw.write("\t{value: " + codeAndStatus[0] + ",label: '" + codeAndStatus[1] + "'},");
                    bw.newLine();
                }
                bw.write("]");
                bw.newLine();
                bw.write("const " + MyStringUtils.lowerCaseFirstLetter(fieldInfo.getPropertyName()) +"PageItemOptions = [");
                bw.newLine();
                bw.write("\t{value: '',label: '全部'},");
                bw.newLine();
                bw.write("\t..." + MyStringUtils.lowerCaseFirstLetter(fieldInfo.getPropertyName()) + "Options");
                bw.newLine();
                bw.write("]");
                bw.newLine();
            }
            bw.write("");
            bw.newLine();

            bw.write("// 添加");
            bw.newLine();
            bw.write("const insert" + tableInfo.getBeanName() + " = () => {");
            bw.newLine();
            for(FieldInfo fieldInfo : keyFields){
                bw.write("\t" + beanNameForm + "." + MyStringUtils.lowerCaseFirstLetter(fieldInfo.getPropertyName()) + " = null;");
                bw.newLine();
            }
            bw.write("\tresetUpload" + tableInfo.getBeanName() + "Form()");
            bw.newLine();
            bw.write("\t" + beanName + "Visible.value = true;");
            bw.newLine();
            bw.write("}");
            bw.newLine();
            bw.write("// 修改");
            bw.newLine();
            bw.write("const update" + tableInfo.getBeanName() + " = (row) => {");
            bw.newLine();
            for(FieldInfo fieldInfo : tableInfo.getFieldList()){
                if(ArrayUtils.contains(ConstantsVue.IGNORE_VUE_FIELDS,MyStringUtils.lowerCaseFirstLetter(fieldInfo.getPropertyName()))){
                    continue;
                }
                if(fieldEnumList.contains(fieldInfo)){
                    bw.write("\t" + beanNameForm + "." + MyStringUtils.lowerCaseFirstLetter(fieldInfo.getPropertyName()) + " = row."
                            + MyStringUtils.lowerCaseFirstLetter(fieldInfo.getPropertyName()) + ".code;");
                }else {
                    bw.write("\t" + beanNameForm + "." + MyStringUtils.lowerCaseFirstLetter(fieldInfo.getPropertyName())
                            + " = row." + MyStringUtils.lowerCaseFirstLetter(fieldInfo.getPropertyName()) + ";");
                }
                bw.newLine();
            }
            bw.write("\t" + beanName + "Visible.value = true;");
            bw.newLine();
            bw.write("}");
            bw.newLine();
            bw.newLine();
            List<FieldInfo> keys = keyIndexMap.get("PRIMARY");
            FieldInfo fieldInfo = keys.get(0);
            String primaryKey = MyStringUtils.lowerCaseFirstLetter(fieldInfo.getPropertyName());
            String primaryKeyUpper = MyStringUtils.upperCaseFirstLetter(fieldInfo.getPropertyName());
            bw.write("const " + beanName + "SummitRef = ref()");
            bw.newLine();
            bw.write("// 提交数据进行添加或保存");
            bw.newLine();
            bw.write("const summit" + tableInfo.getBeanName() + " = (" + beanName + "SummitRef) => {");
            bw.newLine();
            bw.write("\t" + beanName + "SummitRef.validate((valid) => {");
            bw.newLine();
            bw.write("\t\tif(valid){");
            bw.newLine();
            bw.write("\t\t\tif("+ beanNameForm +"." + primaryKey + " == null){");
            bw.newLine();
            bw.write("\t\t\tadd" + tableInfo.getBeanName() + "(" + beanNameForm + ").then((res) => {");
            bw.newLine();
            bw.write("\t\t\t\tif(res.data.code == 200){");
            bw.newLine();
            ElementMessage(bw,"res.data.data","success","\t\t\t\t\t");
            bw.write("\t\t\t\t\tgetPage" + tableInfo.getBeanName() + "()");
            bw.newLine();
            bw.write("\t\t\t\t\t} else {");
            bw.newLine();
            ElementMessage(bw,"res.data.message", "error", "\t\t\t\t\t");
            bw.write("\t\t\t\t}");
            bw.newLine();
            bw.write("\t\t\t}).catch((error) => {");
            bw.newLine();
            ElementMessage(bw,"error.message","error","\t\t\t\t");
            bw.write("\t\t\t})");
            bw.newLine();
            bw.write("\t\t\t}else{");
            bw.newLine();
            bw.write("\t\t\t\tupdate" + tableInfo.getBeanName() + "By" + primaryKeyUpper + "("+ beanNameForm + ", " + beanNameForm + "." + primaryKey +").then((res) => {");
            bw.newLine();
            bw.write("\t\t\t\tif(res.data.code == 200){");
            bw.newLine();
            ElementMessage(bw,"res.data.data","success","\t\t\t\t\t");
            bw.write("\t\t\t\t\tgetPage" + tableInfo.getBeanName() + "()");
            bw.newLine();
            bw.write("\t\t\t\t\t} else {");
            bw.newLine();
            ElementMessage(bw,"res.data.message", "error", "\t\t\t\t\t");
            bw.write("\t\t\t\t}");
            bw.newLine();
            bw.write("\t\t\t}).catch((error) => {");
            bw.newLine();
            ElementMessage(bw,"error.message","error","\t\t\t\t");
            bw.write("\t\t\t})");
            bw.newLine();
            bw.write("\t\t\t\t}");
            bw.newLine();
            bw.write("\t\t\t" + beanName + "Visible.value = false;");
            bw.newLine();
            bw.write("\t\t}");
            bw.newLine();
            bw.write("\t})");
            bw.newLine();
            bw.write("}");
            bw.newLine();
            bw.newLine();

            bw.write("// 删除");
            bw.newLine();
            bw.write("const delete" + tableInfo.getBeanName() + " = (row) => {");
            bw.newLine();
            bw.write("\tElMessageBox.confirm(");
            bw.newLine();
            bw.write("\t\t'是否要删除',");
            bw.newLine();
            bw.write("\t\t'Warning',");
            bw.newLine();
            bw.write("\t\t{ confirmButtonText: '删除', cancelButtonText: '取消',type: 'warning',}");
            bw.newLine();
            bw.write("\t).then(() => {");
            bw.newLine();
            bw.write("\t\tdelete" + tableInfo.getBeanName() + "By" + methodName + "(" + execParam + ").then((res) => {");
            bw.newLine();
            ElementMessage(bw,"res.data.message","success","\t\t\t");
            bw.write("\t\t\tgetPage" + tableInfo.getBeanName() + "()");
            bw.newLine();
            bw.write("\t\t})");
            bw.newLine();
            bw.write("\t})");
            bw.newLine();
            bw.write("}");
            bw.newLine();
            bw.newLine();
            // onMounted(() => {
            //  getPageCategory()
            // })
            bw.write("onMounted(() => {");
            bw.newLine();
            bw.write("\tgetPage" + tableInfo.getBeanName() + "()");
            bw.newLine();
            bw.write("})");
            bw.newLine();
            bw.write("</script>");
            bw.newLine();
            bw.newLine();
            bw.write("<style lang=\"scss\">");
            bw.newLine();
            bw.write("</style>");
            bw.newLine();
            bw.flush();
        }catch (Exception e){
            logger.error("生成vue界面: {} 失败" ,beanName);
        }finally {
            if(bw != null){
                try {
                    bw.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            if(outWriter != null){
                try {
                    outWriter.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            if(out != null){
                try {
                    out.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }

    private static void ElementMessage(BufferedWriter bw,String message,String type,String indentation) throws IOException {
        bw.write(indentation + "ElMessage({");
        bw.newLine();
        bw.write(indentation + "\tmessage: " + message + ",");
        bw.newLine();
        bw.write(indentation + "\ttype: '" + type + "',");
        bw.newLine();
        bw.write(indentation + "\tplain: true,");
        bw.newLine();
        bw.write(indentation + "})");
        bw.newLine();
    }

    // 对枚举名称进行处理，携程枚举模式
    private static String[] getCodeAndStatus(String name){
        String[] res = new String[2];
        name = name.replaceAll(" ","");
        int mid = 0;
        for(int i = 0; i < name.length(); i++){
            char c = name.charAt(i);
            if(c >= '0' && c <= '9'){
                mid = i + 1;
            }else{
                break;
            }
        }
        res[0] = name.substring(0,mid);
        res[1] = name.substring(mid);
        if(res[0].isEmpty() && res[1].isEmpty()) {
            return null;
        }
        return res;
    }
}

